package com.czmini.cztest.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.czmini.cztest.common.JenkinsClient;
import com.czmini.cztest.common.ServiceException;
import com.czmini.cztest.constants.UserConstants;
import com.czmini.cztest.dao.*;
import com.czmini.cztest.dto.PageTableRequest;
import com.czmini.cztest.dto.PageTableResponse;
import com.czmini.cztest.dto.ResultDto;
import com.czmini.cztest.dto.TokenDto;
import com.czmini.cztest.dto.jenkins.OperateJenkinsJobDto;
import com.czmini.cztest.dto.jenkins.RequestInfoDto;
import com.czmini.cztest.dto.task.AddZcTestTaskDto;
import com.czmini.cztest.dto.task.QueryZcTestTaskListDto;
import com.czmini.cztest.dto.task.TestTaskDto;
import com.czmini.cztest.entity.*;
import com.czmini.cztest.service.ZcTestTaskService;
import com.czmini.cztest.util.JenkinsUtil;
import com.czmini.cztest.util.StrUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;

import java.io.IOException;
import java.util.*;

/**
 * @ProjectName: cztest
 * @Package: com.czmini.cztest.service.impl
 * @ClassName: ZcTestTaskServiceImpl
 * @Author: 还是那个橙子
 * @Description: 测试任务接口
 * @Date: 2022/5/1 23:41
 * @Version: 1.0
 */

@Slf4j
@Service
public class ZcTestTaskServiceImpl implements ZcTestTaskService {

    @Autowired
    private JenkinsClient jenkinsClient;
    @Autowired
    private ZcTestTaskMapper zcTestTaskMapper;
    @Autowired
    private ZcTestJenkinsMapper zcTestJenkinsMapper;
    @Autowired
    private ZcTestCaseMapper zcTestCaseMapper;
    @Autowired
    private ZcTestTaskMapper zctestTaskMapper;
    @Autowired
    private ZcTestTaskCaseRelMapper zcTestTaskCaseRelMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDto<ZcTestTask> update(ZcTestTask zcTestTask) {
        ZcTestTask queryTestTask = new ZcTestTask();
        queryTestTask.setId(zcTestTask.getId());
        queryTestTask.setCreateUserId(zcTestTask.getCreateUserId());

        ZcTestTask resultTestTask = zctestTaskMapper.selectOne(queryTestTask);
        if (Objects.isNull(resultTestTask)) {
            throw new ServiceException("测试任务不存在");
        }
        //更新时间
        resultTestTask.setUpdateTime(new Date());
        resultTestTask.setName(zcTestTask.getName());
        resultTestTask.setRemark(zcTestTask.getRemark());

        zctestTaskMapper.updateByPrimaryKeySelective(resultTestTask);


        return  ResultDto.success("成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDto<ZcTestTask> save(TestTaskDto testTaskDto, Integer taskType) {
        StringBuilder testCommand = new StringBuilder();

        // 获取测试任务
        AddZcTestTaskDto teskTask = testTaskDto.getTeskTask();
        List<Integer> caseIdlist = testTaskDto.getCaseIdlist();

        ZcTestJenkins queryTestJenkins = new ZcTestJenkins();
        queryTestJenkins.setId(teskTask.getTestJenkinsId());
        queryTestJenkins.setCreateUserId(teskTask.getCreateUserId());

        //查询jenkins信息
        ZcTestJenkins jenkinsresult = zcTestJenkinsMapper.selectOne(queryTestJenkins);
        if(Objects.isNull(jenkinsresult)){
            return ResultDto.fail("Jenkins信息为空");
        }

        //todo  根据用户选择的id  查询测试用例
        List<ZcTestCase> zcTestCaseList = zcTestCaseMapper.selectByIds(StrUtil.list2IdsStr(caseIdlist));
        //生成测试命令
        makeTestCommand(testCommand, jenkinsresult,zcTestCaseList);

        ZcTestTask zcTestTask = new ZcTestTask();

        zcTestTask.setName(teskTask.getName());
        zcTestTask.setTestJenkinsId(teskTask.getTestJenkinsId());
        zcTestTask.setCreateUserId(teskTask.getCreateUserId());
        zcTestTask.setRemark(teskTask.getRemark());

        zcTestTask.setTaskType(taskType);
        zcTestTask.setTestCommand(testCommand.toString());
        zcTestTask.setCaseCount(caseIdlist.size());
        zcTestTask.setStatus(UserConstants.STATUS_ONE);
        zcTestTask.setCreateTime(new Date());
        zcTestTask.setUpdateTime(new Date());

        zctestTaskMapper.insert(zcTestTask);
        if(Objects.nonNull(caseIdlist) && caseIdlist.size()>0){
            List<ZcTestTaskCaseRel> testTaskCaseList = new ArrayList<>();
            for (Integer testCaseId:caseIdlist) {
                ZcTestTaskCaseRel zcTestTaskCaseRel = new ZcTestTaskCaseRel();
                zcTestTaskCaseRel.setTaskId(zcTestTask.getId());
                zcTestTaskCaseRel.setCaseId(testCaseId);
                zcTestTaskCaseRel.setCreateUserId(zcTestTask.getCreateUserId());
                zcTestTaskCaseRel.setCreateTime(new Date());
                zcTestTaskCaseRel.setUpdateTime(new Date());
                testTaskCaseList.add(zcTestTaskCaseRel);
            }
            log.info("=====测试任务详情保存-落库入参====："+ JSONObject.toJSONString(testTaskCaseList));
            zcTestTaskCaseRelMapper.insertList(testTaskCaseList);
        }
        return ResultDto.success("成功", zcTestTask);
    }

    // 拼接测试命令
    private void makeTestCommand(StringBuilder testCommand,ZcTestJenkins zcTestJenkins,List<ZcTestCase> zcTestCaseList) {
        //打印测试目录
        testCommand.append("pwd");
        testCommand.append("\n");
        if(Objects.isNull(zcTestJenkins)){
            throw new ServiceException("组装测试命令时，Jenkins信息为空");
        }
        if(Objects.isNull(zcTestCaseList) || zcTestCaseList.size()==0){
            throw new ServiceException("组装测试命令时，测试用例列表信息为空");
        }
        // 获取Jenkins的运行命令
        String runCommand = zcTestJenkins.getTestCommand();

        Integer commandRunCaseType = zcTestJenkins.getCommandRunCaseType();
        String systemTestCommand = zcTestJenkins.getTestCommand();

        if(StringUtils.isEmpty(systemTestCommand)){
            throw new ServiceException("组装测试命令时，运行的测试命令信息为空");
        }
        //默认文本类型
        if(Objects.isNull(commandRunCaseType)){
            commandRunCaseType = 1;
        }
        //文本类型
        if(commandRunCaseType==1){
            //遍历
            for (ZcTestCase hogwartsTestCase :zcTestCaseList) {
                //拼装命令前缀
                testCommand.append(systemTestCommand).append(" ");
                //拼装测试数据
                testCommand.append(hogwartsTestCase.getCaseData())
                        .append("\n");
            }
        }
        //文件类型
        if(commandRunCaseType==2) {
            String commandRunCaseSuffix = zcTestJenkins.getCommandRunCaseSuffix();
            if(StringUtils.isEmpty(commandRunCaseSuffix)){
                throw new ServiceException("组装测试命令且case为文件时，测试用例后缀名不能为空");
            }

            //遍历
            for (ZcTestCase zcTestCase :zcTestCaseList) {
                //拼装下载文件的curl命令
                makeCurlCommand(testCommand, zcTestCase, commandRunCaseSuffix);
                testCommand.append("\n");
                //拼装命令前缀
                testCommand.append(systemTestCommand).append(" ");
                //平台测试用例名称
                testCommand.append(zcTestCase.getCaseName())
                        //拼装.分隔符
                        .append(".")
                        //拼装case文件后缀
                        .append(commandRunCaseSuffix)
                        .append(" || true")
                        .append("\n");
            }
            log.info("testCommand.toString()== "+testCommand.toString() + "  runCommand== " + runCommand);
            testCommand.append("\n");
        }
        }

        // 拼接测试命令
    private void makeCurlCommand(StringBuilder testCommand, ZcTestCase zcTestCase, String commandRunCaseSuffix) {
        //通过curl命令获取测试数据并保存为文件
        testCommand.append("curl ")
                .append("-o ");
        String caseName = zcTestCase.getCaseName();
        if(StringUtils.isEmpty(caseName)){
            caseName = "测试用例无测试名称";
        }
        testCommand.append(caseName)
                .append(".")
                .append(commandRunCaseSuffix)
                .append(" ${aitestBaseUrl}/testCase/data/")
                .append(zcTestCase.getId())
                .append(" -H \"token: ${token}\" ");
        //本行命令执行失败，继续运行下面的命令行
        testCommand.append(" || true");
        testCommand.append("\n");
    }

    //
    @Override
    public ResultDto<ZcTestTask> getById(Integer taskId, Integer createUserId) {
        ZcTestTask queryTestTask = new ZcTestTask();
        queryTestTask.setId(taskId);
        queryTestTask.setCreateUserId(createUserId);

        ZcTestTask zcTestTaskResult = zcTestTaskMapper.selectOne(queryTestTask);

        if (Objects.isNull(taskId)) {
            ResultDto.fail("任务id不能为空");
        }
        return ResultDto.success("成功", zcTestTaskResult);

    }

    @Override
    public ResultDto<ZcTestTask> delete(Integer taskId, Integer createUserId) {
        ZcTestTask queryTestTask = new ZcTestTask();
        queryTestTask.setId(taskId);
        queryTestTask.setCreateUserId(createUserId);

        ZcTestTask zcTestTaskResult = zcTestTaskMapper.selectOne(queryTestTask);
        if (Objects.isNull(zcTestTaskResult)) {
            ResultDto.fail("任务信息不能为空");
        }
        zctestTaskMapper.deleteByPrimaryKey(taskId);

        return ResultDto.success("成功");
    }

    @Override
    public ResultDto<PageTableResponse<ZcTestTask>> list(PageTableRequest<QueryZcTestTaskListDto> pageTableRequest) {
        //获取数据
        QueryZcTestTaskListDto queryZcTestTaskListDto = pageTableRequest.getParams();
        //创建查询条件
        Integer pageSize = pageTableRequest.getPageSize();
        Integer pageNum = pageTableRequest.getPageNum();
        //总记录数
        Integer count = zctestTaskMapper.count(queryZcTestTaskListDto);
        //分页查询
        List<ZcTestTask> zcTestTasks = zctestTaskMapper.list(queryZcTestTaskListDto,
                (pageNum - 1) * pageSize, pageSize);

        PageTableResponse<ZcTestTask> zcTestTaskPageTableResponse =new PageTableResponse<>();
        zcTestTaskPageTableResponse.setRecordsTotal(count);
        zcTestTaskPageTableResponse.setData(zcTestTasks);

        return ResultDto.success("成功", zcTestTaskPageTableResponse);
    }

    /**
     * 更新任务状态
     * @param zcTestTask
     * @return
     */
    @Override
    public ResultDto<ZcTestTask> updateTaskStatus(ZcTestTask zcTestTask) {
        ZcTestTask querytestTask = new ZcTestTask();
        querytestTask.setId(zcTestTask.getId());
        querytestTask.setCreateUserId(zcTestTask.getCreateUserId());

        ZcTestTask zcTestTaskResult = zcTestTaskMapper.selectOne(querytestTask);

        if (Objects.isNull(zcTestTaskResult)) {
            ResultDto.fail("任务信息不能为空");
        }
        //如果任务已经完成，则不重复修改
        if(UserConstants.STATUS_THREE.equals(zcTestTaskResult.getStatus())){
            return ResultDto.fail("测试任务已完成，无需修改");
        }
        zcTestTaskResult.setUpdateTime(new Date());

        //仅状态为已完成时修改
        if(UserConstants.STATUS_THREE.equals(zcTestTask.getStatus())){
            zcTestTaskResult.setBuildUrl(zcTestTask.getBuildUrl());
            zcTestTaskResult.setStatus(UserConstants.STATUS_THREE);
            zcTestTaskMapper.updateByPrimaryKey(zcTestTaskResult);
        }
        return  ResultDto.success("成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDto startTask(TokenDto tokenDto, ZcTestTask zcTestTask, RequestInfoDto requestInfoDto) throws IOException {
        log.info("开始执行任务，入参"+JSONObject.toJSONString(requestInfoDto)+"++++"+JSONObject.toJSONString(zcTestTask));
        //校验参数，Jenkins 是否有效
        if (Objects.isNull(zcTestTask)) {
            return ResultDto.fail("测试任务参数不能为空");
        }
        Integer defaultJenkinsId = tokenDto.getDefaultJenkinsId();
        if (Objects.isNull(defaultJenkinsId)) {
            return ResultDto.fail("未配置jenkins信息");
        }
        ZcTestJenkins queryzcTestJenkins = new ZcTestJenkins();
        queryzcTestJenkins.setId(defaultJenkinsId);
        queryzcTestJenkins.setCreateUserId(tokenDto.getUserId());

        ZcTestJenkins resultzcTestJenkins = zcTestJenkinsMapper.selectOne(queryzcTestJenkins);
        if (Objects.isNull(resultzcTestJenkins)) {
            return ResultDto.fail("默认Jenkins不存在或已失效");
        }
        ZcTestTask querytestTask = new ZcTestTask();
        querytestTask.setId(zcTestTask.getId());
        querytestTask.setCreateUserId(zcTestTask.getCreateUserId());        //创建人id
        //根据测试id查询测试任务
        ZcTestTask resulttestTask = zctestTaskMapper.selectOne(querytestTask);

        if (Objects.isNull(resulttestTask)) {
            String tips = "未查到测试任务";
            log.info(tips+querytestTask.getId());
            return ResultDto.fail(tips);
        }
        //获取测试命令 更新状态
        String testCommandStr = zcTestTask.getTestCommand();
        if (StringUtils.isEmpty(testCommandStr)) {
            testCommandStr = resultzcTestJenkins.getTestCommand();
        }
        if(StringUtils.isEmpty(testCommandStr)){
            return ResultDto.fail("任务的测试命令不能为空");
        }
        //更新任务状态 为 执行中
        resulttestTask.setStatus(UserConstants.STATUS_TWO);
        zctestTaskMapper.updateByPrimaryKeySelective(resulttestTask);

        //拼接测试命令
        StringBuilder testCommand = new StringBuilder();
        //添加保存测试任务接口拼装的mvn test 命令
        testCommand.append(testCommandStr);
        testCommand.append("\n");

        // todo 获取更新任务的Jenkins信息 的回调地址
        StringBuilder updateTaskStatusUrl = JenkinsUtil.getUpdateTaskStatusUrl(requestInfoDto, resulttestTask);
        //构建jenkins参数组装
        HashMap<String, String> params = new HashMap<>();

        params.put("aitestBaseUrl",requestInfoDto.getBaseUrl());
        params.put("token",requestInfoDto.getToken());
        params.put("testCommand",testCommand.toString());
        params.put("updateStatusData",updateTaskStatusUrl.toString());


        log.info("=====执行测试Job的构建参数组装====：" +JSONObject.toJSONString(params));
        log.info("=====执行测试Job的修改任务状态的数据组装====：" +updateTaskStatusUrl);

        OperateJenkinsJobDto operateJenkinsJobDto = new OperateJenkinsJobDto();
        operateJenkinsJobDto.setParams(params);
        operateJenkinsJobDto.setTokenDto(tokenDto);
        operateJenkinsJobDto.setZcTestJenkins(resultzcTestJenkins);

        operateJenkinsJobDto.setParams(params);

        ResultDto resultDto =jenkinsClient.operateJenkinsJob(operateJenkinsJobDto);

        //此处抛出异常，阻止事务提交
        if(0 == resultDto.getResultCode()){
            throw new ServiceException("执行测试时异常-"+resultDto.getMessage());
        }
        return resultDto;

    }
}
